//
// Copyright 2010 Marcel Urbanek
// 
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// 
//      http://www.apache.org/licenses/LICENSE-2.0
// 
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
package de.urbiworx.typewriter;

import java.io.IOException;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.util.HashMap;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;

import javax.faces.FactoryFinder;
import javax.faces.context.FacesContext;
import javax.faces.context.ResponseStream;
import javax.faces.context.ResponseWriter;
import javax.faces.context.ResponseWriterWrapper;
import javax.faces.render.RenderKit;
import javax.faces.render.RenderKitFactory;
import javax.faces.render.Renderer;
import javax.faces.render.ResponseStateManager;

public class FoRenderKit extends RenderKit {
	private static final String FALLBACK_RENDERKIT = "HTML_BASIC";
	private Map rendererFamilies=new HashMap();
	Logger logger=Logger.getLogger("de.urbiworx.typewriter");
	
	public void addRenderer(String family, String rendererType,
			Renderer renderer) {
		if (family == null || rendererType == null || renderer == null) {
			// PENDING - i18n
			String message = "Argument Error: One or more parameters are null.";
			message = message + " family " + family + " rendererType "
					+ rendererType + " renderer " + renderer;
			throw new NullPointerException(message);

		}
		HashMap renderers = null;

		synchronized (rendererFamilies) {
			if (null == (renderers = (HashMap) rendererFamilies.get(family))) {
				rendererFamilies.put(family, renderers = new HashMap());
			}
			renderers.put(rendererType, renderer);
		}
	}

	public Renderer getRenderer(String family, String rendererType) {
		if (rendererType == null || family == null) {
			// PENDING - i18n
			String message = "Argument Error: One or more parameters are null.";
			message = message + " family " + family + " rendererType "
					+ rendererType;
			throw new NullPointerException(message);
		}
		HashMap renderers = null;
		Renderer renderer = null;
		if (null != (renderers = (HashMap) rendererFamilies.get(family))) {
			renderer = (Renderer) renderers.get(rendererType);
		}
		if (renderer==null){
			FacesContext context=FacesContext.getCurrentInstance();
			RenderKitFactory factory=(RenderKitFactory) FactoryFinder.getFactory(FactoryFinder.RENDER_KIT_FACTORY);
			renderer=factory.getRenderKit(context, FALLBACK_RENDERKIT).getRenderer(family,rendererType);
		}
		return renderer;
	}
	@Override
	public ResponseStream createResponseStream(OutputStream stream) {
		try {
			return new FoJsfOutputStream();
		} catch (IOException e) {
			logger.log(Level.WARNING, "Error while creating buffered output stream", e);
			return null;
		}
	}

	@Override
	public ResponseWriter createResponseWriter(Writer origWriter, String contentTypeList,
			String characterEncoding) {
		FacesContext context=FacesContext.getCurrentInstance();
		RenderKitFactory factory=(RenderKitFactory) FactoryFinder.getFactory(FactoryFinder.RENDER_KIT_FACTORY);
		try {
			final FoJsfOutputStream outputStream= new FoJsfOutputStream();
			final ResponseWriter writer=factory.getRenderKit(context, FALLBACK_RENDERKIT).createResponseWriter(new OutputStreamWriter(outputStream), contentTypeList, characterEncoding);
			return new ResponseWriterWrapper(){

				@Override
				public ResponseWriter cloneWithWriter(Writer writer) {
					//We dont use the writer anyway...
					return this;
				}

				@Override
				protected ResponseWriter getWrapped() {
					return writer;
				}
				
			};
		} catch (IOException e) {
			logger.log(Level.WARNING, "Error while creating buffered output stream", e);
			return null;
		}
	}


	@Override
	public ResponseStateManager getResponseStateManager() {
		FacesContext context=FacesContext.getCurrentInstance();
		RenderKitFactory factory=(RenderKitFactory) FactoryFinder.getFactory(FactoryFinder.RENDER_KIT_FACTORY);
		return factory.getRenderKit(context, FALLBACK_RENDERKIT).getResponseStateManager();
	}
	

}
